#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/iio/consumer.h>
#include <linux/uaccess.h>


static int myadc_open(struct inode *inode, struct file *filp);
static ssize_t myadc_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt);
static ssize_t myadc_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt);
static int myadc_release(struct inode *inode, struct file *filp);
int myadc_probe(struct platform_device *);
int myadc_remove(struct platform_device *);
long myadc_unlocked_ioctl(struct file * file, unsigned int cmd, unsigned long arg);

/*********************************************************************************************/

#define myadc_CNT   1	/* 设备号个数 */
#define myadc_NAME  "myadc"	/* 名字 */

#define CMD_READ_SCALE _IOR('A',1,int)
/*********************************************************************************************/



/*********************************************************************************************/
 /* myadc 设备结构体 */
 struct myadc_dev{
	dev_t devid; /* 设备号 */
	int major;
	int minor;


	struct cdev cdev; /* cdev */
	struct class *class; /* 类 */
	struct device *device; /* 设备 */
	struct device_node *nd; /* 设备节点 */

	struct iio_channel * adc_channel;

	int adc_raw_value;

 };

 struct myadc_dev myadc; /* myadc 设备 */



const struct of_device_id myadc_match_table[] = {
	{.compatible = "myadc"},
	{}
};

struct platform_driver myadc_platform_driver={
	.driver ={
		.name = "myadc",
		.of_match_table = myadc_match_table,
	},
	.probe = myadc_probe,
	.remove = myadc_remove,
};

/*********************************************************************************************/



/*********************************************************************************************/
/* 设备操作函数 */
static struct file_operations myadc_fops = {
	.owner = THIS_MODULE,
	.open = myadc_open,
	.read = myadc_read,
	.write = myadc_write,
	.release = 	myadc_release,
	.unlocked_ioctl = myadc_unlocked_ioctl,
};
/*********************************************************************************************/


int myadc_probe(struct platform_device *pdev)
{
	int ret = 0;


	/* 注册字符设备驱动 */
	/* 1、创建设备号 */	
	ret = alloc_chrdev_region(&myadc.devid, 0, myadc_CNT, myadc_NAME);	/* 申请设备号 */
	if(ret<0){
		printk("[ERROR] alloc_chrdev_region failed\n");
	}
	printk("[OK] This is myadc_probe\n");
	
	/* 2、初始化cdev */
	myadc.cdev.owner = THIS_MODULE;
	cdev_init(&myadc.cdev, &myadc_fops);
	
	/* 3、添加一个cdev */
	ret = cdev_add(&myadc.cdev, myadc.devid, myadc_CNT);
		
	/* 4、创建类 */
	myadc.class = class_create(THIS_MODULE, myadc_NAME);


	/* 5、创建设备 */
	myadc.device = device_create(myadc.class, NULL, myadc.devid, NULL, myadc_NAME);


	/*获取ADC设备*/
	myadc.adc_channel =   iio_channel_get(&(pdev->dev),NULL);

	return ret;
}
int myadc_remove(struct platform_device *dev)
{

	return 0;
}

long myadc_unlocked_ioctl(struct file * file, unsigned int cmd, unsigned long arg)
{
	int ret;
	switch(cmd)
	{
		case CMD_READ_SCALE:
			iio_read_channel_raw(myadc.adc_channel,&myadc.adc_raw_value);
			ret = copy_to_user((int *)arg,&myadc.adc_raw_value,sizeof(myadc.adc_raw_value));
			break;
		default:
			break;
	}

	return 0;
}
/*
 * @description		: 打开设备
 * @param - inode 	: 传递给驱动的inode
 * @param - filp 	: 设备文件，file结构体有个叫做private_data的成员变量
 * 					  一般在open的时候将private_data指向设备结构体。
 * @return 			: 0 成功;其他 失败
 */
static int myadc_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &myadc; /* 设置私有数据 */
	return 0;
}

/*
 * @description		: 从设备读取数据 
 * @param - filp 	: 要打开的设备文件(文件描述符)
 * @param - buf 	: 返回给用户空间的数据缓冲区
 * @param - cnt 	: 要读取的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 读取的字节数，如果为负值，表示读取失败
 */
static ssize_t myadc_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{

	return 0;
}

/*
 * @description		: 向设备写数据 
 * @param - filp 	: 设备文件，表示打开的文件描述符
 * @param - buf 	: 要写给设备写入的数据
 * @param - cnt 	: 要写入的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 写入的字节数，如果为负值，表示写入失败
 */
static ssize_t myadc_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{

	return 0;
}

/*
 * @description		: 关闭/释放设备
 * @param - filp 	: 要关闭的设备文件(文件描述符)
 * @return 			: 0 成功;其他 失败
 */
static int myadc_release(struct inode *inode, struct file *filp)
{

	return 0;
}


/*
 * @description	: 驱动入口函数 
 * @param 		: 无
 * @return 		: 0 成功;其他 失败
 */
static int __init myadc_init(void)
{
	int ret = 0;

	/* 6、注册platform设备 */
	platform_driver_register(&myadc_platform_driver);
	
	return ret;
}

/*
 * @description	: 驱动出口函数
 * @param 		: 无
 * @return 		: 无
 */
static void __exit myadc_exit(void)
{
	/*  1. 删除cdev */
	cdev_del(&myadc.cdev);
	/* 2. 注销设备号 */
	unregister_chrdev_region(myadc.devid, myadc_CNT); 
	/* 3. 注销设备 */
	device_destroy(myadc.class, myadc.devid);
	/* 4. 注销类 */
	class_destroy(myadc.class);
	/* 5. 注销platform设备 */
	platform_driver_unregister(&myadc_platform_driver);
}

/* 
 * 将上面两个函数指定为驱动的入口和出口函数 
 */
module_init(myadc_init);
module_exit(myadc_exit);

/* 
 * LICENSE和作者信息
 */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("fangjunjie");